/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = sqlserver_core.h                                              */
/*  NOTE      =                                                               */
/*  DATE      = 2014/09/28 by zhengxd                                         */
/******************************************************************************/
#ifndef _SQLSERVER_CORE_H_
#define _SQLSERVER_CORE_H_

#include "sqlserver_base_type.h"

/*
 *  分片包数据
*/
typedef struct __st_L7_fragment_sqlserver {
    int i_end_packet_flg;                 /* packet结束flag */
    int i_residual_packet_head_len;       /* 残留packet的头数据长度 */
    char arr_residual_packet_head[8];     /* 残留packet的头数据 */
    unsigned long ui_total_len;          /* 实际数据总长度 */
    unsigned long ui_remain_len;         /* 还需要接受的数据长度 */
    unsigned long ui_parsed_index;       /* 解析到的位置 */
    Frbyte_Packet *p_st_data;             /* packet数据 */
    struct timeval st_first_timestamp;   /* 第一个分片包的时间 */
    struct timeval st_end_timestamp;     /* 最后一个分片包的时间 */
} L7_fragment_sqlserver;

/*
 *   L7session_sqlserver 用于存放sqlserver私有的session数据, 对应L7_session的p_session_private变量
 *    通用的username、session_starttime、session_stoptime
*/
typedef struct __st_L7session_sqlserver {
    LITTLE_BIG_ENDIAN i_endian;            /* 网络字节序 */
    Frtds_type_float i_float_type;         /* 浮点型 */
    char *p_cli_host_user;                /* 客户端的主机名 */
    char *p_program;                      /* 客户端的程序名 */
    char *p_db_name;                      /* 数据库名 */
    char *p_db_user;                      /* 登陆用户名 */
    char *p_tds_charset;                  /* TDS charset */
    struct timeval st_login;              /* login成功时间 */
    int i_cli_tds_ver;                    /* 客户端使用的TDS协议版本 */
    int i_cli_tds_min_ver;                /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最低版本类型 */
    int i_cli_tds_max_ver;                /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最高版本类型 */
    int i_ser_tds_ver;                    /* 服务端使用的TDS协议版本 */
    int i_ser_tds_min_ver;                /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最低版本类型 */
    int i_ser_tds_max_ver;                /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最高版本类型 */
    char arr_client_charset[20];          /* 客户端的charset */
} L7session_sqlserver;

/*
 *  sql server请求
 *  对应L7_requestdata中的p_request_private数据
*/
typedef struct __st_L7_req_sqlserver {
    uint8_t u8_packet_type;               /* 当前packet类型 */
    uint8_t u8_request_type;              /* request类型 */
    uint16_t u16_rpc_type;                /* rpc类型 */
    int i_need_req_resp;                  /* 下一个所需数据类型 */
    int i_cancel_flg;                     /* NORMAL(0)/IGNORE(1)/ATTENTION(2) */
    int i_cli_tds_ver_tmp;                /* 客户端使用的TDS协议版本 */
    int i_cli_tds_min_ver_tmp;            /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最低版本类型 */
    int i_cli_tds_max_ver_tmp;            /* 在未取得LOGIN过程时, 根据packet信息中一些字段大致定位最高版本类型 */
    unsigned int ui_batch_count;          /* 解析到batch的位置 */
    unsigned int ui_bind_count;           /* 解析到一个batch中的bind的位置 */
    long l_uid;                           /* prepare ID或者cursor ID */
    Sql_statement *p_st_statement;        /* 对应游标数据 */
    Sql_resultset *p_st_resultset;        /* 对应结果集索引 */
    Sql_field_bind *p_st_bind;            /* 对应参数列表索引 */
} L7_req_sqlserver;

/*
 *  sql server响应
 *  解析response过程中的数据
*/
typedef struct __st_L7_resp_sqlserver {

    char *p_charset;                           /* charset */
    char *p_error_msg;                         /* 错误信息 */
    Frlist_header st_altmetadata_header;       /* altmetadata信息 */
    Frlist_header st_colmetadata_header;       /* colmetadata信息 */
    int i_useful_id;                           /* 用于prepare ID或者Cursor ID */
    int i_ser_tds_ver_tmp;                     /* 服务端使用的TDS协议版本 */
    int i_ser_tds_min_ver_tmp;                 /* 在未取得LOGIN过程时,根据packet信息中一些字段大致定位最低版本类型 */
    int i_ser_tds_max_ver_tmp;                 /* 在未取得LOGIN过程时,根据packet信息中一些字段大致定位最高版本类型 */
    long long l_error_num;                    /* 错误号 */
    unsigned int ui_return_value_count;       /* return value个数 */
    long long arr_return_values[128];         /* return value值 */
    unsigned int ui_sql_effect_count;         /* sql statement个数 */
    unsigned long arr_sql_effect_rows[10240];     /* sql statement值 */
    unsigned int ui_rpc_effect_count;         /* rpc个数 */
    unsigned long arr_rpc_effect_rows[10240]; /* rpc值 */

}L7_resp_sqlserver;

/*
 *  游标ID信息
*/
typedef struct __st_mssql_cursor {
    long l_cursor_id;                     /* cursor ID */
    long l_prepare_id;                    /* cursor ID对应的prepare ID */
    Sql_statement *p_st_statement;        /* prepare数据索引 */
    Sql_resultset *p_st_resultset;        /* cursor ID对应结果集索引 */
} Mssql_cursor;

/*
 *  MSSQL私有数据
*/
typedef struct __st_L7session_sqlserver_private {
    int i_in_session;                     /* session flag */
    L7_fragment_sqlserver *p_st_fragment; /* 分片包数据 */
    L7session_sqlserver *p_st_sess;       /* session数据 */
    L7_req_sqlserver *p_st_req;           /* request数据 */
    L7_resp_sqlserver *p_st_resp;         /* 临时response信息 */
    Frhash_header *p_hash_prepare;        /* prepare数据(Sql_statement *) */
    Frlist_header list_cursor;            /* cursor数据(Mssql_cursor *) */
} L7session_sqlserver_private;

int sqlserver_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet);

int sqlserver_analysis(Conntrack *p_st_conn
                      , Apm_packet *p_st_packet
                      , Frhash_header *p_st_hash_report);

int sqlserver_session_format(void *p_private_session
                            , Frlist_header *p_lst_header
                            , int *p_i_status);

int sqlserver_request_format(void *p_private_session
                            , Frlist_header *p_st_lst_hdr_req
                            , Frtrans_info *p_st_trans_info);

int sqlserver_response_format(void *p_private_session
                             , Frlist_header *p_st_lst_hdr_req
                             , Frlist_header *p_st_lst_hdr_resp
                             , Frtrans_info *p_st_trans_info);

int sqlserver_session_destroy(void *p_private_session);

#endif
